package com.lagou.edu.spring.core.processors;

import com.lagou.edu.spring.annotations.Autowired;
import com.lagou.edu.spring.core.ApplicationContext;
import com.lagou.edu.spring.core.BeanDefinition;
import com.lagou.edu.spring.core.BeanDefinitionRegistry;
import com.lagou.edu.spring.core.BeanFactoryPostProcessor;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Autowired注解解析器
 * 该解析器会扫描容器中所有的bean定义信息，获取这些bean类型中的标注有@Autowired的属性
 * 修改添加这些bean的依赖信息
 * 解析@PostConstruct注解方法，并将这些方法设置成定义信息的初始化方法
 *
 * @author 大犬
 * @date 2020/4/2
 */
public class AutowiredParserProcessor implements BeanFactoryPostProcessor {

    @Override
    public void afterProcessBeanFactory(BeanDefinitionRegistry beanDefinitionRegistry, ApplicationContext applicationContext) {
        List<BeanDefinition> allBeanDefinitions = beanDefinitionRegistry.getAllBeanDefinitions();
        allBeanDefinitions.stream().peek(this::parseAutowiredField)
                .forEach(this::parseInitMethod);
    }

    private void parseInitMethod(BeanDefinition beanDefinition) {
        Class beanType = beanDefinition.getBeanType();
        Method[] declaredMethods = beanType.getDeclaredMethods();
        List<Method> methodList = Arrays.stream(declaredMethods)
                .filter(method -> method.getAnnotation(PostConstruct.class) != null)
                .peek(method -> method.setAccessible(true))
                .collect(Collectors.toList());
        beanDefinition.setInitMethods(methodList);
    }

    private void parseAutowiredField(BeanDefinition beanDefinition) {
        Class beanType = beanDefinition.getBeanType();
        Field[] declaredFields = beanType.getDeclaredFields();
        Map<String, Field> dependencePropertyNames = new HashMap<>(5);
        for (Field declaredField : declaredFields) {
            Autowired autowired = declaredField.getAnnotation(Autowired.class);
            if (autowired == null) {
                continue;
            }
            declaredField.setAccessible(true);
            String dependencePropertyName;
            if (autowired.value().isEmpty()) {
                dependencePropertyName = declaredField.getType().getSimpleName();
            } else {
                dependencePropertyName = autowired.value();
            }
            dependencePropertyNames.put(dependencePropertyName, declaredField);
        }
        if (!dependencePropertyNames.isEmpty()) {
            beanDefinition.setPropertyDependencies(dependencePropertyNames);
        }
    }
}
